<template>
  <div class="chat-container">
    <el-card :body-style="{padding:'0px'}">
      <div slot="header" class="clearfix">
        <span>通话本</span>
        <el-button style="float: right; padding: 3px 0" type="text"
                   @click="options.chatShow=!options.chatShow"
        >
          当前在线人数: {{ Object.getOwnPropertyNames(users).length - 1 }}
        </el-button>
      </div>
      <ul>
        <transition-group name="folder"
                          enter-active-class="animation-slide-top"
        >
          <li v-for="(user, index) in users" :key="user+index" class="text item" v-show="options.chatShow">
            <span :class="[user_name===index ? 'green_color' : 'red_color']">
              {{ index }}</span>
            <span>{{ user ? '(在线)' : '(正在通话)' }}</span>
          </li>
        </transition-group>
      </ul>
    </el-card>
    <el-card>
      <el-row :gutter="10" type="flex" justify="center">
        <el-col :span="10">
          <video ref="localVideo" v-if="!options.isLeave" class="localVideo" autoplay></video>
        </el-col>
        <el-col :span="10">
          <video ref="remoteVideo" class="remoteVideo" :src="remote_video" autoplay></video>
        </el-col>

        <el-col :span="4" align="center">
          <el-input v-model="call_username" placeholder="呼叫用户" style="width: 50%"></el-input>
          <el-button type="primary" @click="call">呼叫</el-button>
        </el-col>
      </el-row>
    </el-card>

    <el-dialog
      title="提示"
      :visible.sync="options.messageShow"
      width="30%"
    >
      <h4>您有视频邀请，是否接受?</h4>
      <span slot="footer" class="dialog-footer">
              <el-button @click="accept">接受</el-button>
              <el-button @click="reject">拒绝</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import config from '@/config';
import socket from '@/utils/socket';

navigator.getUserMedia = navigator.getUserMedia || navigator.mozGetUserMedia || navigator.webkitGetUserMedia;
window.RTCPeerConnection = window.RTCPeerConnection || window.mozRTCPeerConnection || window.webkitRTCPeerConnection;
window.RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate || window.webkitRTCIceCandidate;
window.RTCSessionDescription =
  window.RTCSessionDescription || window.mozRTCSessionDescription || window.webkitRTCSessionDescription;

const configuration = {
  iceServers: [config.DEFAULT_ICE_SERVER]
};

let localStream, peerConn;
let connectedUser = null;

export default {
  data() {
    return {
      user_name: this.$store.state.user.User,
      show: true,
      users: '',
      call_username: '',
      remote_video: '',
      options: {
        chatShow: false,
        messageShow: false,
        isLeave: false
      }

    };
  },
  mounted() {
    let self = this;
    self.options.isLeave = false;
    socket.on(
      'message',
      data => {
        // console.log(data)
        switch (data.event) {
          case 'show':
            self.users = data.allUsers;
            break;
          case 'join':
            self.handleLogin(data);
            break;
          case 'call':
            self.handleCall(data);
            break;
          case 'accept':
            self.handleAccept(data);
            break;
          case 'offer':
            self.handleOffer(data);
            break;
          case 'candidate':
            self.handleCandidate(data);
            break;
          case 'msg':
            self.handleMsg(data);
            break;
          case 'answer':
            self.handleAnswer(data);
            break;
          case 'leave':
            self.handleLeave();
            break;
          default:
            break;
        }
      }
    );
    this.submit();
    this.initCreate();
  },
  beforeDestroy() {
    let localVideo = this.$refs['localVideo'];
    let remoteVideo = this.$refs['remoteVideo'];
    this.closeVideoCall(peerConn, localVideo, remoteVideo);
    this.options.isLeave = true;
  },
  methods: {
    submit() {
      if (this.user_name !== '') {
        this.send({
          event: 'join',
          name: Math.random()
        });
      }
    },
    send(message) {
      if (connectedUser !== null) {
        message.connectedUser = connectedUser;
      }
      socket.send(JSON.stringify(message));
    },
    handleLogin(data) {
      if (data.success === false) {
        this.$alert('该用户名已存在, 请重新输入');
      } else {
        this.show = false;
        this.users = data.allUsers;
        this.initCreate();
      }
    },
    addVideoURL(element, stream) {
      try {
        element.srcObject = stream;
      } catch (e) {
        console.log(e.name + '出错啦,');
      }
    },
    initCreate() {
      let self = this;
      let video = self.$refs['localVideo'];

      navigator.mediaDevices
        .getUserMedia({ audio: true, video: true })
        .then(stream => {
          self.addVideoURL(video, stream);
          video.muted = true;
          localStream = stream;
        })
        .catch(err => {
          console.log(err.name + ': ' + err.message);
        });
    },
    call() {
      if (this.call_username.length > 0) {
        if (this.users[this.call_username] === true) {
          connectedUser = this.call_username;
          this.createConnection();
          this.send({
            event: 'call'
          });
        } else {
          this.$alert('当前用户正在被呼叫');
        }
      } else {
        this.$alert('请输入用户名');
      }
    },
    createConnection() {
      let self = this;
      let remoteVideo = self.$refs['remoteVideo'];

      peerConn = new RTCPeerConnection(configuration);
      peerConn.addStream(localStream);
      peerConn.onaddstream = (e) => {
        self.addVideoURL(remoteVideo, e.stream);
      };
      peerConn.onicecandidate = (event) => {
        setTimeout(() => {
          if (event.candidate) {
            self.send({
              event: 'candidate',
              candidate: event.candidate
            });
          }
        });
      };
    },
    handleCall(data) {
      this.options.messageShow = true;
      connectedUser = data.name;
    },
    reject() {
      this.options.messageShow = false;
      this.send({
        event: 'reject',
        accept: false
      });
    },
    accept() {
      this.options.messageShow = false;
      this.send({
        event: 'accept',
        accept: true
      });
    },
    handleAccept(data) {
      if (data.accept) {
        peerConn.createOffer(
          offer => {
            this.send({
              event: 'offer',
              offer: offer
            });
            peerConn.setLocalDescription(offer);
          },
          error => {
            this.$alert('创建通话失败,请重试一次');
          }
        );
      } else {
        this.$alert('对方已拒绝');
      }
    },
    async handleOffer(data) {
      connectedUser = data.name;
      await this.createConnection();
      await peerConn.setRemoteDescription(new RTCSessionDescription(data.offer));
      // Create an answer to an offer
      await peerConn.createAnswer(
        answer => {
          peerConn.setLocalDescription(answer);
          this.send({
            event: 'answer',
            answer: answer
          });
        },
        error => {
          this.$alert(error.name + 'Error when creating an answer');
        }
      );
    },
    handleMsg(data) {
      console.log(data.message);
    },
    handleAnswer(data) {
      peerConn.setRemoteDescription(new RTCSessionDescription(data.answer));
    },
    handleCandidate(data) {
      // ClientB 通过 PeerConnection 的 AddIceCandidate 方法保存起来
      peerConn.addIceCandidate(new RTCIceCandidate(data.candidate));
    },
    hangUp() {
      this.send({
        event: 'leave'
      });
      this.handleLeave();
    },
    handleLeave() {
      this.$alert('通话已结束');
      connectedUser = null;
      this.remote_video = '';
      peerConn.close();
      peerConn.onicecandidate = null;
      peerConn.onaddstream = null;
      if (peerConn.signalingState === 'closed') {
        this.initCreate();
      }
    },
    closePreview() {
      this.options.chatShow = false;
    },
    closeVideoCall(peerConn, localVideo, remoteVideo) {
      this.handleLeave();
      if (peerConn) {
        peerConn.ontrack = null;
        peerConn.onremovetrack = null;
        peerConn.onremovestream = null;
        peerConn.onicecandidate = null;
        peerConn.oniceconnectionstatechange = null;
        peerConn.onsignalingstatechange = null;
        peerConn.onicegatheringstatechange = null;
        peerConn.onnegotiationneeded = null;
        if (remoteVideo.srcObject) {
          remoteVideo.srcObject.getTracks().forEach(track => track.stop());
        }

        if (localVideo.srcObject) {
          localVideo.srcObject.getTracks().forEach(track => track.stop());
        }
        peerConn.close();
        peerConn = null;
      }
      remoteVideo.removeAttribute('src');
      remoteVideo.removeAttribute('srcObject');
      localVideo.removeAttribute('src');
      remoteVideo.removeAttribute('srcObject');
      this.$alert('视频通话已结束');

    }
  }
};
</script>
<style scoped lang="scss">
.chat-container {
  .title {
    text-align: center;
    color: #050210;
    user-select: none;
    text-shadow: 5px 0 5px rgba(102, 109, 102, 0.49);

  }

  .green_color {
    color: #00e676;

    &::after {
      content: "(me)";
    }
  }


  .chat-controller {
    position: fixed;
    background-color: transparent;
    border-radius: 2em;
    border: 3px dashed #ff6550;
    padding: 5px;
    margin: 0 auto;
    outline: none;
    color: #00e676;
    cursor: pointer;
    z-index: 9999;
    bottom: 1em;
    left: 49%;
    width: 10em;
  }

}

</style>
